//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>
#include "ddktstthread.h"
#include "ddktstserver.h"

int g_nRet;
int g_nErr;

class CDDKTstThread : public CDeviceDriver
{
public:
    CARAPI Read(
        /* [in] */ UInt64 u64Offset,
        /* [in] */ UInt32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ UInt64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ UInt32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    virtual void Dispose();

public:
    ECode Initialize();

public:
};

//------------------------------------------------------------------------------
int thread1(void *parg)
{
    g_nRet++;

    return 0;
}
ECode CreateThread1()
{
    ECode ec = NOERROR;
    IThread *iThread = NULL;

    ec = DzCreateKernelThread(thread1, NULL, 0, ThreadPriorityRank_Normal, &iThread);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread1 error, 0x%08x\n", ec);
        return ec;
    }

    iThread->Join(INFINITE, NULL);
    iThread->Release();

    if (1 == g_nRet) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
int thread2(void *parg)
{
    int i = (int)parg;
    if (5 == i) g_nRet++;
    return 0;
}
ECode CreateThread2()
{
    ECode ec = NOERROR;
    IThread *iThread = NULL;

    ec = DzCreateKernelThread(thread2, (void *)5, 0, ThreadPriorityRank_Normal, &iThread);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread2 error, 0x%08x\n", ec);
        return ec;
    }

    iThread->Join(INFINITE, NULL);
    iThread->Release();

    if (1 == g_nRet) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
int thread3(void *parg)
{
    if (!memcmp(parg, L"elastos", 8)) {
        g_nRet++;
    }

    return 0;
}
ECode CreateThread3()
{
    ECode ec = NOERROR;
    IThread *iThread = NULL;
    WString wstrBuf = L"elastos";

    ec = DzCreateKernelThread(thread3, (void *)wstrBuf, 0, ThreadPriorityRank_Normal, &iThread);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread3 error, 0x%08x\n", ec);
        return ec;
    }

    iThread->Join(INFINITE, NULL);
    iThread->Release();

    if (1 == g_nRet) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
int thread4(void *parg)
{
    int nId = 0;
    char chThread = ((PThreadPack)parg)->chThread;
    int nIdThread = ((PThreadPack)parg)->nIdThread;
    kprintf("chThread: %c\n", chThread);
    kprintf("nIdThread: %d\n", nIdThread);

    ((PThreadPack)parg)->iThread->GetId(&nId);
    kprintf("nId: %d\n", nId);

    if (('a' == chThread) && (nId == nIdThread)) {
        g_nRet++;
    }

    return 0;
}
ECode CreateThread4()
{
    ECode ec = NOERROR;
    int nId = 0;
    IThread *iThread = NULL;
    IThread *iCurThread = NULL;
    ThreadPack stThreadPack;

    ec = DzGetCurrentThread(&iCurThread);
    if (FAILED(ec)) {
        kprintf("DzGetCurrentThread error, 0x%08x\n", ec);
        return ec;
    }
    ec = iCurThread->GetId(&nId);
    if (FAILED(ec)) {
        kprintf("GetId error\n");
        iCurThread->Release();
        return ec;
    }

    stThreadPack.chThread = 'a';
    stThreadPack.nIdThread = nId;
    stThreadPack.iThread = iCurThread;
    ec = DzCreateKernelThread(thread4, &stThreadPack, 0, ThreadPriorityRank_Normal, &iThread);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread4 error, 0x%08x\n", ec);
        iCurThread->Release();
        return ec;
    }

    iThread->Join(INFINITE, NULL);
    iThread->Release();
    iCurThread->Release();

    if (1 == g_nRet) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
ECode CreateThread5(UInt32 uRoutine)
{
    ECode ec = NOERROR;
    IThread *iThread = NULL;

    kprintf("routine: 0x%08x\n", uRoutine);

    ec = DzCreateKernelThread((PThreadMain)uRoutine,
                              NULL,
                              0,
                              ThreadPriorityRank_Normal,
                              &iThread);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread5 error, 0x%08x\n", ec);
        return ec;
    }

    iThread->Join(INFINITE, NULL);
    iThread->Release();
    return ec;
}

//------------------------------------------------------------------------------
int thread6(void *parg)
{
    g_nRet++;

    return 0;
}
ECode CreateThread6(int nCaseFlag)
{
    ECode ec = NOERROR;
    IThread *iThread = NULL;

    kprintf("nRand: %d\n", nCaseFlag);

    ec = DzCreateKernelThread(thread6,
                              NULL,
                              CreateThreadFlag_System,
                              (ThreadPriorityRank)nCaseFlag,
                              &iThread);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread6 error, 0x%08x\n", ec);
        return ec;
    }

    iThread->Join(INFINITE, NULL);
    iThread->Release();

    if (1 == g_nRet) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
int thread8(void *parg)
{
    g_nRet++;

    return 0;
}
ECode CreateThread8()
{
    ECode ec = NOERROR;

    ec = DzCreateKernelThread(thread8,
                              NULL,
                              CreateThreadFlag_System,
                              ThreadPriorityRank_Normal,
                              NULL);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread8 error, 0x%08x\n", ec);
        return ec;
    }

    DzSleep(DzMillisecondsToTicks(1000), NULL);

    if (1 == g_nRet) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
int thread99(void *parg)
{
    while (1);
    return 0;
}
int thread9(void *parg)
{
    ECode ec = NOERROR;
    IThread **iGrandThread = (IThread **)parg;

    ec = DzCreateKernelThread(thread99,
                              NULL,
                              0,
                              ThreadPriorityRank_Normal,
                              iGrandThread);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread99 error, 0x%08x\n", ec);
        return ec;
    }

    return 0;
}
ECode CreateThread9()
{
    ECode ec = NOERROR;
    IThread *iThread = NULL, *iGrandThread = NULL;
    ThreadState thState;

    ec = DzCreateKernelThread(thread9,
                              (void *)(&iGrandThread),
                              0,
                              ThreadPriorityRank_Normal,
                              &iThread);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread9 error, 0x%08x\n", ec);
        return ec;
    }

    iThread->Join(INFINITE, NULL);

    iThread->GetState(&thState);
    if (ThreadState_Finished != thState) {
        kprintf("iThread not finished, %d\n", thState);
        g_nRet++;
    }

    DzSleep(DzMillisecondsToTicks(1000), NULL);
    iGrandThread->GetState(&thState);
    if (ThreadState_Running != thState) {
        kprintf("iGrandThread not running, %d\n", thState);
        g_nRet++;
    }
    iGrandThread->Abort();
    iThread->Release();
    iGrandThread->Release();

    if (!g_nRet) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
int thread10(void *parg)
{
    ECode ec = NOERROR;
    int i = (int)parg;
    i++;
    g_nRet++;
    IThread *iThread = NULL;

    if (i < 20) {
        ec = DzCreateKernelThread(thread10, (void *)i, 0, ThreadPriorityRank_Normal, &iThread);
        if (FAILED(ec)) {
            kprintf("DzCreateKernelThread thread10 error, 0x%08x\n", ec);
            return ec;
        }

        iThread->Join(INFINITE, NULL);
        iThread->Release();
    }

    return g_nRet;
}
ECode CreateThread10()
{
    ECode ec = NOERROR;
    IThread *iThread = NULL;
    int nFinishCode = 0;

    ec = DzCreateKernelThread(thread10, (void *)0, 0, ThreadPriorityRank_Normal, &iThread);
    if (FAILED(ec)) {
        kprintf("DzCreateKernelThread thread10 error, 0x%08x\n", ec);
        return ec;
    }

    iThread->Join(INFINITE, NULL);
    iThread->GetExitCode(&nFinishCode);
    iThread->Release();

    if (nFinishCode == 20) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
IEvent *g_Event = NULL;
int thread11(void *parg)
{
    WaitResult wr;
    g_nRet++;
    g_Event->Wait(&wr, NULL);
    return 0;
}
ECode CreateThread11()
{
    const int nThreadNum = 20;
    ECode ec = NOERROR;
    IThread *iThread[nThreadNum];
    int i;

    ec = DzCreateEventObj(TRUE, 0, &g_Event);
    if (FAILED(ec)) {
        kprintf("DzCreateEventObj error, 0x%08x\n", ec);
        return ec;
    }

    for (i = 0; i < nThreadNum; i++) {
        ec = DzCreateKernelThread(thread11, NULL, 0, ThreadPriorityRank_Normal, &iThread[i]);
        if (FAILED(ec)) {
            kprintf("DzCreateKernelThread thread error, %d, 0x%08x\n", i, ec);
            g_Event->Notify(1);
            while (i >= 0) {
                iThread[i]->Join(INFINITE, NULL);
                iThread[i]->Release();
                i--;
            }
            g_Event->Release();
            return ec;
        }
    }

    g_Event->Notify(1);
    for (i = 0; i < nThreadNum; i++) {
        iThread[i]->Join(INFINITE, NULL);
        iThread[i]->Release();
    }
    g_Event->Release();

    if (g_nRet == 20) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
int thread12(void *parg)
{
    g_nRet++;
    return 0;
}
ECode CreateThread12()
{
    const int nRunTimes = 10000;
    ECode ec = NOERROR;
    IThread *iThread = NULL;
    int i;

    for (i = 0; i < nRunTimes; i++) {
        ec = DzCreateKernelThread(thread12, NULL, 0, ThreadPriorityRank_Normal, &iThread);
        if (FAILED(ec)) {
            kprintf("DzCreateKernelThread thread12 error, %d, 0x%08x\n", i, ec);
            return ec;
        }

        iThread->Join(INFINITE, NULL);
        iThread->Release();
        iThread = NULL;
    }

    if (g_nRet == nRunTimes) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
ECode DzGetCurThd1()
{
    IThread *iCurThread = NULL;
    int nId = 0;
    ECode ec = NOERROR;

    ec = DzGetCurrentThread(&iCurThread);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        return ec;
    }
    ec = iCurThread->GetId(&nId);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        return ec;
    }
    return ec;
}

//------------------------------------------------------------------------------
int g_nId;
int getcurthread2(void *parg)
{
    ECode ec = NOERROR;
    IThread *iSubThread = NULL;

    ec = DzGetCurrentThread(&iSubThread);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        return ec;
    }
    ec = iSubThread->GetId(&g_nId);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
    }
    iSubThread->Release();

    return ec;
}
ECode DzGetCurThd2(int nCaseFlag)
{
    IThread *iSubThread = NULL;
    int nId = 0;
    ECode ec = NOERROR;

    switch (nCaseFlag) {
        case ThreadType_Kernel:
            ec = DzCreateKernelThread(getcurthread2, NULL, 0, ThreadPriorityRank_Normal, &iSubThread);
            if (FAILED(ec)) {
                kprintf("%d, 0x%08x\n", __LINE__, ec);
                return ec;
            }
            break;

        case ThreadType_SystemNormal:
            ec = DzCreateKernelThread(getcurthread2, NULL, 1, ThreadPriorityRank_Normal, &iSubThread);
            if (FAILED(ec)) {
                kprintf("%d, 0x%08x\n", __LINE__, ec);
                return ec;
            }
            break;

        case ThreadType_SystemSoftRealTime:
            ec = DzCreateKernelThread(getcurthread2, NULL, 1, ThreadPriorityRank_SoftRealTime, &iSubThread);
            if (FAILED(ec)) {
                kprintf("%d, 0x%08x\n", __LINE__, ec);
                return ec;
            }
            break;

        default:
            kprintf("Unknown ThreadType.\n");
            break;
    }

    iSubThread->GetId(&nId);
    iSubThread->Join(INFINITE, NULL);
    iSubThread->Release();

    if (g_nId == nId) {
        return NOERROR;
    }
    else {
        return E_DDKTST_ERROR1;
    }
}

//------------------------------------------------------------------------------
ECode DzGetCurThd5()
{
    IThread *iSubThread = NULL;
    ECode ec = NOERROR;
    int i, nRunTimes = 10000;

    for (i = 0; i < nRunTimes; i++) {
        ec = DzGetCurrentThread(&iSubThread);
        if (FAILED(ec)) {
            kprintf("%d, 0x%08x\n", __LINE__, ec);
            return ec;
        }
        iSubThread->Release();
    }

    return ec;
}

//------------------------------------------------------------------------------
int getcurthread6(void *parg)
{
    int i, nRunTimes = 10000;
    IThread *iSubThread = NULL;
    ECode ec = NOERROR;

    for (i = 0; i < nRunTimes; i++) {
        ec = DzGetCurrentThread(&iSubThread);
        if (FAILED(ec)) {
            kprintf("%d, 0x%08x\n", __LINE__, ec);
            return ec;
        }
        else {
            iSubThread->Release();
        }
    }

    return 0;
}
ECode DzGetCurThd6()
{
    IThread *iSubThread = NULL;
    ECode ec = NOERROR;

    ec = DzCreateKernelThread(getcurthread6, NULL, 0, ThreadPriorityRank_SoftRealTime, &iSubThread);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        return ec;
    }

    iSubThread->Join(INFINITE, NULL);
    iSubThread->Release();
    return ec;
}

//------------------------------------------------------------------------------
int preemptionthread12(void *parg)
{
    DzSleep(DzMillisecondsToTicks(1000), NULL);
    g_nRet = 1;
    return 0;
}
int preemptionthread11(void *parg)
{
    Boolean bPre;

    bPre = DzDisablePreemption();
    DzDelay(3 * 1000 * 1000);
    if (g_nRet != 0) g_nErr = 1;
    DzRestorePreemption(bPre);

    DzDelay(3 * 1000 * 1000);
    if (g_nRet != 1) g_nErr = 2;

    return 0;
}
ECode ThdTstPreemption1()
{
    IThread *iSubThread[2];
    ECode ec = NOERROR;

    ec = DzCreateKernelThread(preemptionthread11,
                              NULL,
                              0,
                              ThreadPriorityRank_Normal,
                              &iSubThread[0]);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        return ec;
    }

    ec = DzCreateKernelThread(preemptionthread12,
                              iSubThread[0],
                              0,
                              ThreadPriorityRank_Normal,
                              &iSubThread[1]);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        iSubThread[0]->Release();
        return ec;
    }

    iSubThread[0]->Join(INFINITE, NULL);
    iSubThread[0]->Release();
    iSubThread[1]->Join(INFINITE, NULL);
    iSubThread[1]->Release();

    kprintf("g_nErr: %d\n", g_nErr);
    if (!g_nErr)
        return NOERROR;
    else
        return E_DDKTST_ERROR1;
}

//------------------------------------------------------------------------------
int preemptionthread22(void *parg)
{
    Boolean bPre;

    bPre = DzDisablePreemption();
    DzDelay(3 * 1000 * 1000);
    if (g_nRet != 1) g_nErr = 1;
    g_nRet = 2;
    DzRestorePreemption(bPre);

    return 0;
}
int preemptionthread21(void *parg)
{
    g_nRet = 1;
    DzDelay(3 * 1000 * 1000);
    if (g_nRet != 2) g_nErr = 2;
    return 0;
}
ECode ThdTstPreemption2()
{
    IThread *iSubThread[2];
    ECode ec = NOERROR;
    g_nRet = 0;

    ec = DzCreateKernelThread(preemptionthread21,
                              NULL,
                              0,
                              ThreadPriorityRank_Normal,
                              &iSubThread[0]);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        return ec;
    }

    ec = iSubThread[0]->SetPriority(ThreadPriority_AboveNormal);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        iSubThread[0]->Release();
        return ec;
    }
    DzSleep(DzMillisecondsToTicks(100), NULL);

    ec = DzCreateKernelThread(preemptionthread22,
                              iSubThread[0],
                              0,
                              ThreadPriorityRank_Normal,
                              &iSubThread[1]);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        iSubThread[0]->Release();
        return ec;
    }

    iSubThread[0]->Join(INFINITE, NULL);
    iSubThread[0]->Release();
    iSubThread[1]->Join(INFINITE, NULL);
    iSubThread[1]->Release();

    kprintf("g_nErr: %d\n", g_nErr);
    if (!g_nErr)
        return NOERROR;
    else
        return E_DDKTST_ERROR1;
}

//------------------------------------------------------------------------------
int preemptionthread32(void *parg)
{
    Boolean bPre;

    bPre = DzDisablePreemption();
    DzDelay(3 * 1000 * 1000);
    g_nRet = 2;
    DzRestorePreemption(bPre);

    return 0;
}
int preemptionthread31(void *parg)
{
    g_nRet = 1;
    DzSleep(DzMillisecondsToTicks(3000), NULL);
    if (g_nRet != 2) g_nErr = 2;
    return 0;
}
ECode ThdTstPreemption3()
{
    IThread *iSubThread[2];
    ECode ec = NOERROR;
    g_nRet = 0;

    ec = DzCreateKernelThread(preemptionthread31,
                              NULL,
                              1,
                              ThreadPriorityRank_SoftRealTime,
                              &iSubThread[0]);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        return ec;
    }

    ec = DzCreateKernelThread(preemptionthread32,
                              iSubThread[0],
                              0,
                              ThreadPriorityRank_Normal,
                              &iSubThread[1]);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        iSubThread[0]->Release();
        return ec;
    }

    iSubThread[0]->Join(INFINITE, NULL);
    iSubThread[0]->Release();
    iSubThread[1]->Join(INFINITE, NULL);
    iSubThread[1]->Release();

    kprintf("g_nErr: %d\n", g_nErr);
    if (!g_nErr)
        return NOERROR;
    else
        return E_DDKTST_ERROR1;
}

//------------------------------------------------------------------------------
int preemptionthread42(void *parg)
{
    g_nRet = 1;
    return 0;
}
int preemptionthread41(void *parg)
{
    Boolean bPre1, bPre2;
    int i;

    bPre1 = DzDisablePreemption();
    for (i = 0; i < 10000000; i++) {
        if (g_nRet != 0) g_nErr = 1;
    }

    bPre2 = DzDisablePreemption();
    for (i = 0; i < 10000000; i++) {
        if (g_nRet != 0) g_nErr = 2;
    }

    DzRestorePreemption(bPre2);
    for (i = 0; i < 10000000; i++) {
        if (g_nRet != 0) g_nErr = 3;
    }

    DzRestorePreemption(bPre1);
    for (i = 0; i < 10000000; i++) {
        if (g_nRet != 1) g_nErr = 4;
    }

    return 0;
}
ECode ThdTstPreemption4()
{
    IThread *iSubThread[2];
    ECode ec = NOERROR;

    ec = DzCreateKernelThread(preemptionthread41,
                              NULL,
                              0,
                              ThreadPriorityRank_Normal,
                              &iSubThread[0]);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        return ec;
    }
    DzYield();

    ec = DzCreateKernelThread(preemptionthread42,
                              iSubThread[0],
                              0,
                              ThreadPriorityRank_Normal,
                              &iSubThread[1]);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        iSubThread[0]->Release();
        return ec;
    }

    iSubThread[0]->Join(INFINITE, NULL);
    iSubThread[0]->Release();
    iSubThread[1]->Join(INFINITE, NULL);
    iSubThread[1]->Release();

    kprintf("g_nErr: %d\n", g_nErr);
    if (!g_nErr)
        return NOERROR;
    else
        return E_DDKTST_ERROR1;
}

//------------------------------------------------------------------------------
extern uint_t g_uElapsedTicks;
int preemptionthread51(void *parg)
{
    Boolean bPre;
    uint_t uTimerTicks = 0;

    bPre = DzDisablePreemption();

    uTimerTicks = g_uElapsedTicks;
    DzDelay(2 * 1000 * 1000);
    if (uTimerTicks == g_uElapsedTicks) g_nErr = 1;

    DzRestorePreemption(bPre);

    return 0;
}
ECode ThdTstPreemption5()
{
    IThread *iSubThread = NULL;
    ECode ec = NOERROR;

    ec = DzCreateKernelThread(preemptionthread51,
                              NULL,
                              0,
                              ThreadPriorityRank_Normal,
                              &iSubThread);
    if (FAILED(ec)) {
        kprintf("%d, 0x%08x\n", __LINE__, ec);
        return ec;
    }

    iSubThread->Join(INFINITE, NULL);
    iSubThread->Release();

    if (!g_nErr)
        return NOERROR;
    else
        return E_DDKTST_ERROR1;
}

//------------------------------------------------------------------------------
int preemptionthread61(void *parg)
{
    Boolean bPre;

    bPre = DzDisablePreemption();

    int i, nStep = (int)parg;

    for (i = 0; i < 1000000; i++) {
        g_nRet += nStep;
    }

    if ((2000000 != g_nRet) && (3000000 != g_nRet) && (7000000 != g_nRet) &&
        (5000000 != g_nRet) && (9000000 != g_nRet) && (10000000 != g_nRet)
        && (12000000 != g_nRet)) {
        g_nErr = 1;
    }

    DzRestorePreemption(bPre);

    return 0;
}
ECode ThdTstPreemption6()
{
    const int nThreadNum = 3;
    IThread *iSubThread[nThreadNum];
    int i, nStep[nThreadNum] = {2, 3, 7};
    ECode ec = NOERROR;

    for (i = 0; i < nThreadNum; i++) {
        ec = DzCreateKernelThread(preemptionthread61,
                                  (void *)nStep[i],
                                  0,
                                  ThreadPriorityRank_Normal,
                                  &iSubThread[i]);
        if (FAILED(ec)) {
            kprintf("%d, 0x%08x\n", __LINE__, ec);
            while (i >= 0) {
                iSubThread[i]->Join(INFINITE, NULL);
                iSubThread[i]->Release();
                i--;
            }
            return ec;
        }
    }

    for (i = 0; i < nThreadNum; i++) {
        iSubThread[i]->Join(INFINITE, NULL);
        iSubThread[i]->Release();
    }

    if (!g_nErr)
        return NOERROR;
    else
        return E_DDKTST_ERROR1;
}

//------------------------------------------------------------------------------
extern IDeviceDriver * CDECL CreateDDKTstThread(uint_t uDeviceNo, void *pvParameter)
{
    CDDKTstThread *pThreadTstServer = new CDDKTstThread;
    if (NULL == pThreadTstServer) {
        kprintf("ERROR: new CDDKTstThread: Not enough memory!\n");
        return NULL;
    }

    kprintf("CreateDDKTstThread\n");

    ECode ec = pThreadTstServer->Initialize();
    if (FAILED(ec)) {
        delete pThreadTstServer;
        return NULL;
    }

    pThreadTstServer->AddRef();

    return pThreadTstServer;
}

ECode CDDKTstThread::Initialize()
{
    return NOERROR;
}

ECode CDDKTstThread::Read(
    /* [in] */ UInt64 u64Offset,
    /* [in] */ UInt32 bytesToRead,
    /* [out] */ MemoryBuf * pBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode CDDKTstThread::Write(
    /* [in] */ UInt64 u64Offset,
    /* [in] */ const MemoryBuf & buffer,
    /* [out] */ UInt32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode CDDKTstThread::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ const MemoryBuf & inBuffer,
    /* [out] */ MemoryBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec = E_DDKTST_ERROR1;
    g_nRet = 0;
    g_nErr = 0;

    PThreadControl pThreadControl = (PThreadControl)inBuffer.GetPayload();
    if (pThreadControl == NULL) {
        return E_OUT_OF_MEMORY;
    }

    switch (nControlCode) {
        case ThdTst_DzCreateKernelThread:
            switch (pThreadControl->nFunNo) {
                case 1:
                    ec = CreateThread1();
                    break;
                case 2:
                    ec = CreateThread2();
                    break;
                case 3:
                    ec = CreateThread3();
                    break;
                case 4:
                    ec = CreateThread4();
                    break;
                case 5:
                    ec = CreateThread5(pThreadControl->uRoutine);
                    break;
                case 6:
                    ec = CreateThread6(pThreadControl->nCaseFlag);
                    break;
                case 8:
                    ec = CreateThread8();
                    break;
                case 9:
                    ec = CreateThread9();
                    break;
                case 10:
                    ec = CreateThread10();
                    break;
                case 11:
                    ec = CreateThread11();
                    break;
                case 12:
                    ec = CreateThread12();
                    break;
            }
            break;

        case ThdTst_DzGetCurrentThread:
            switch (pThreadControl->nFunNo) {
                case 1:
                    ec = DzGetCurThd1();
                    break;
                case 2:
                    ec = DzGetCurThd2(pThreadControl->nCaseFlag);
                    break;
                case 5:
                    ec = DzGetCurThd5();
                    break;
                case 6:
                    ec = DzGetCurThd6();
                    break;
            }
            break;

        case ThdTst_DzYield:
            switch (pThreadControl->nFunNo) {
                case 1:
                    ec = ThdTstDzYield1();
                    break;
                case 2:
                    ec = ThdTstDzYield2();
                    break;
                case 3:
                    ec = ThdTstDzYield3();
                    break;
                case 4:
                    ec = ThdTstDzYield4();
                    break;
                case 5:
                    ec = ThdTstDzYield5();
                    break;
            }
            break;

        case ThdTst_DzSleep:
            switch (pThreadControl->nFunNo) {
                case 1:
                    ec = ThdTstDzSleep1();
                    break;
                case 2:
                    ec = ThdTstDzSleep2();
                    break;
                case 3:
                    ec = ThdTstDzSleep3();
                    break;
                case 4:
                    ec = ThdTstDzSleep4();
                    break;
                case 5:
                    ec = ThdTstDzSleep5();
                    break;
                case 6:
                    ec = ThdTstDzSleep6();
                    break;
                case 7:
                    ec = ThdTstDzSleep7();
                    break;
                case 8:
                    ec = ThdTstDzSleep8();
                    break;
                case 9:
                    ec = ThdTstDzSleep9();
                    break;
            }
            break;

        case ThdTst_DzDelay:
            switch (pThreadControl->nFunNo) {
                case 1:
                    ec = ThdTstDzDelay1();
                    break;
                case 2:
                    ec = ThdTstDzDelay2();
                    break;
                case 3:
                    ec = ThdTstDzDelay3();
                    break;
            }
            break;

        case ThdTst_DzPreemption:
            switch (pThreadControl->nFunNo) {
                case 1:
                    ec = ThdTstPreemption1();
                    break;
                case 2:
                    ec = ThdTstPreemption2();
                    break;
                case 3:
                    ec = ThdTstPreemption3();
                    break;
                case 4:
                    ec = ThdTstPreemption4();
                    break;
                case 5:
                    ec = ThdTstPreemption5();
                    break;
                case 6:
                    ec = ThdTstPreemption6();
                    break;
            }
            break;

        default:
            kprintf("Unknown ThreadTstServer Command.\n");
            break;
    }

    return ec;
}

void CDDKTstThread::Dispose()
{
    delete this;
}
